using System;
using System.Collections;
using System.Text;

namespace csammisrun.OscarLib.Utility
{
	/// <summary>
	/// Provides static methods for processing messages in SNAC family 0x000D -- chat room navigation service
	/// </summary>
	internal static class SNAC0D
	{
    /// <summary>
		/// Sends a request for parameter information -- SNAC(0D,02)
		/// </summary>
		/// <param name="sess">A <see cref="Session"/> object</param>
		public static void RequestParametersList(Session sess)
		{
			SNACHeader sh = new SNACHeader();
			sh.FamilyServiceID = (ushort)SNACFamily.ChatNavigationService;
			sh.FamilySubtypeID = (ushort)ChatNavigationService.LimitsRequest;
			sh.Flags = 0x0000;
			sh.RequestID = sess.GetNextRequestID();

      sess.StoreRequestID(sh.RequestID, "parameters");

			DataPacket dp = Marshal.BuildDataPacket(sess, sh, null);
			SNACFunctions.BuildFLAP(dp);
		}

    /// <summary>
    /// Creates a new chat room -- SNAC(0D,08)
    /// </summary>
    /// <param name="sess">A <see cref="Session"/> object</param>
    /// <param name="roomname">The name of the room to create</param>
    /// <param name="exchange">The exchange number of the room</param>
    /// <param name="language">The language to be used in the room</param>
    /// <param name="charset">The charset to be used in the room</param>
    public static void CreateChatRoom(Session sess, string roomname, ushort exchange,
      string language, string charset)
    {
      SNACHeader sh = new SNACHeader();
      sh.FamilyServiceID = (ushort)SNACFamily.ChatNavigationService;
      sh.FamilySubtypeID = (ushort)ChatNavigationService.CreateRoomRequest;
      sh.Flags = 0x0000;
      sh.RequestID = sess.GetNextRequestID();

      byte cmdlength = (byte)Marshal.ASCII.GetByteCount("create");
      ushort roomnamelength = (ushort)Marshal.ASCII.GetByteCount(roomname);
      ushort charsetlength = (ushort)Marshal.ASCII.GetByteCount(charset);
      ushort langlength = (ushort)Marshal.ASCII.GetByteCount(language);

      int index = 0;
      byte[] buffer = new byte[2 + 1 + cmdlength + 2 + 1 + 2 + 4 + roomnamelength +
        4 + charsetlength + 4 + langlength];

      Marshal.InsertUshort(buffer, exchange, ref index);
      buffer[index++] = cmdlength;
      Marshal.InsertString(buffer, "create", Marshal.ASCII, ref index);

      Marshal.InsertUshort(buffer, 0xFFFF, ref index);
      buffer[index++] = 0x01;

      TLV[] tlvs = new TLV[3];
      tlvs[0] = TLVMarshal.MakeTLV(0x00D3, Marshal.StringToByteArray(roomname, Marshal.ASCII));
      tlvs[1] = TLVMarshal.MakeTLV(0x00D6, Marshal.StringToByteArray(charset, Marshal.ASCII));
      tlvs[2] = TLVMarshal.MakeTLV(0x00D7, Marshal.StringToByteArray(language, Marshal.ASCII));

      Marshal.InsertUshort(buffer, (ushort)tlvs.Length, ref index);
      Marshal.InsertTLVs(tlvs, buffer, ref index);

      sess.StoreRequestID(sh.RequestID, "create");

      DataPacket dp = Marshal.BuildDataPacket(sess, sh, buffer);
      SNACFunctions.BuildFLAP(dp);
    }

    /// <summary>
    /// Processes requested chat room information -- SNAC(0D,09)
    /// </summary>
    /// <param name="dp">A <see cref="DataPacket"/> object containing SNAC(0D,09)</param>
    public static void ProcessChatRoomInformation(DataPacket dp)
    {
      string type = (string)dp.ParentSession.RetrieveRequestID(dp.SNAC.RequestID);

      if (type == null)
      {
        dp.ParentSession.OnWarning(ServerErrorCode.UnrequestedChatRoomInformation);
      }
      else if (type == "create")
      {
        ParseRoomCreationInfo(dp);
      }
      else if (type == "parameters")
      {
        ParseChatParameterInfo(dp);
      }
    }

    private static void ParseChatParameterInfo(DataPacket dp)
    {
      ArrayList exchanges = new ArrayList();
      byte maxrooms = 0x00;

      int index = 0;
      while (index < dp.Data.Length)
      {
        ushort key = Marshal.ByteArrayToUshort(dp.Data, ref index);
        ushort keylength = Marshal.ByteArrayToUshort(dp.Data, ref index);

        switch (key)
        {
          case 0x0002:
            maxrooms = dp.Data[index++];
            break;
          case 0x0003:
            exchanges.Add(ParseChatExchangeInfo(dp.Data, ref index, keylength));
            break;
          default:
            index += keylength;
            break;
        }
      }
    }

    private static ChatExchangeInfo ParseChatExchangeInfo(byte[] data, ref int index, int datalength)
    {
      int stopindex = index + datalength;
      ChatExchangeInfo retval = new ChatExchangeInfo();

      retval.Exchange = Marshal.ByteArrayToUshort(data, ref index);

      while (index < stopindex)
      {
        ushort key = Marshal.ByteArrayToUshort(data, ref index);
        ushort keylength = Marshal.ByteArrayToUshort(data, ref index);
        switch (key)
        {
          case 0x0002:
            retval.ClassPermissions = Marshal.ByteArrayToUshort(data, ref index);
            break;
          case 0x00C9:
            retval.Flags = Marshal.ByteArrayToUshort(data, ref index);
            break;
          case 0x00D3:
            retval.Name = Marshal.ByteArrayToString(data, ref index, keylength, Marshal.ASCII);
            break;
          case 0x00D5:
            retval.CreationPermissions = data[index++];
            break;
          case 0x00D6:
            retval.CharSet1 = Marshal.ByteArrayToString(data, ref index, keylength, Marshal.ASCII);
            break;
          case 0x00D7:
            retval.Language1 = Marshal.ByteArrayToString(data, ref index, keylength, Marshal.ASCII);
            break;
          case 0x00D8:
            retval.CharSet2 = Marshal.ByteArrayToString(data, ref index, keylength, Marshal.ASCII);
            break;
          case 0x00D9:
            retval.Language2 = Marshal.ByteArrayToString(data, ref index, keylength, Marshal.ASCII);
            break;
          default:
            index += keylength;
            break;
        }
      }

      return retval;
    }

    private static void ParseRoomCreationInfo(DataPacket dp)
    {
      ChatRoomInfo roominfo = null;
      int index = 0;
      while (index < dp.Data.Length)
      {
        ushort key = Marshal.ByteArrayToUshort(dp.Data, ref index);
        ushort keylength = Marshal.ByteArrayToUshort(dp.Data, ref index);
        switch (key)
        {
          case 0x0004:
            roominfo = ParseInnerCreationInfo(dp.Data, ref index, keylength);
            break;
          default:
            index += keylength;
            break;
        }
      }

      // Join the newly created room
      if (roominfo != null)
      {
        SNAC01.RequestChatService(dp.ParentSession, roominfo);
      }
    }

    private static ChatRoomInfo ParseInnerCreationInfo(byte[] data, ref int index, ushort datalength)
    {
      int stopindex = index + datalength;
      ChatRoomInfo retval = new ChatRoomInfo();

      retval.Exchange = Marshal.ByteArrayToUshort(data, ref index);
      byte strlen = data[index++];
      retval.FullName = Marshal.ByteArrayToString(data, ref index, strlen, Marshal.ASCII);
      retval.Instance = Marshal.ByteArrayToUshort(data, ref index);

      byte detaillevel = data[index++];
      ushort unknown = Marshal.ByteArrayToUshort(data, ref index);

      while (index < stopindex)
      {
        ushort key = Marshal.ByteArrayToUshort(data, ref index);
        ushort keylength = Marshal.ByteArrayToUshort(data, ref index);

        switch (key)
        {
          case 0x006A:
            retval.DisplayName = Marshal.ByteArrayToString(data, ref index, keylength, Marshal.ASCII);
            break;
          case 0x00C9:
            retval.Flags = Marshal.ByteArrayToUshort(data, ref index);
            break;
          case 0x00CA:
            retval.CreationTime = Marshal.ByteArrayToUint(data, ref index);
            break;
          case 0x00D1:
            retval.MaxMessageLength = Marshal.ByteArrayToUshort(data, ref index);
            break;
          case 0x00D2:
            retval.MaxOccupants = Marshal.ByteArrayToUshort(data, ref index);
            break;
          case 0x00D3:
            retval.DisplayName = Marshal.ByteArrayToString(data, ref index, keylength, Marshal.ASCII);
            break;
          case 0x00D5:
            retval.CreationPermissions = data[index++];
            break;
          default:
            index += keylength;
            break;
        }
      }

      return retval;
    }
	}
}
